#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include "include/cppjieba/Jieba.hpp"
#include <mutex>
#include <unordered_set>
#include <list>

namespace ns_util
{
    class FileUtil
    {
    public:
        static bool ReadOnePage(const std::string &path, std::string *page_content)
        {
            std::ifstream ifs(path);
            if (!ifs.is_open())
                return false;
            std::string line;
            while (getline(ifs, line))
            {
                page_content->append(line.begin(), line.end());
            }
            ifs.close();
            return true;
        }
    };

    class StringUtil
    {
    public:
        static void CutString(std::vector<std::string> *v, const std::string &target, const std::string &sep)
        {
            boost::split(*v, target, boost::is_any_of(sep), boost::token_compress_on);
        }
    };

    const char *const DICT_PATH = "./dict/jieba.dict.utf8";
    const char *const HMM_PATH = "./dict/hmm_model.utf8";
    const char *const USER_DICT_PATH = "./dict/user.dict.utf8";
    const char *const IDF_PATH = "./dict/idf.utf8";
    const char *const STOP_WORD_PATH = "./dict/stop_words.utf8";

    class JieBaUtil
    {
    public:
        static void CutForSearchHelper(std::list<std::string> *words_list)
        {
            // 遍历删除停止词
            for (auto iter = words_list->begin(); iter != words_list->end();)
            {
                auto it = _uset.find(*iter);
                if (it == _uset.end()) // 找不到，往后走
                    ++iter;
                else // 等于停止词，删除。注意迭代器失效
                    iter = words_list->erase(iter);
            }
        }
        static void CutForSerach(const std::string &s, std::vector<std::string> *words)
        {
            if (_uset.empty()) // 为空就初始化
                InitJieBaUtil();
            _jieba.CutForSearch(s, *words);
            // 将切分好的数组中的值拷贝到链表中，使用链表进行删除停止词（减少删除挪动消耗的时间）
            std::list<std::string> words_list(words->begin(), words->end());
            CutForSearchHelper(&words_list);
            words->clear();
            for (const std::string &word : words_list) // 再将链表拷贝回数组
            {
                words->push_back(word);
            }
        }

    private:
        static void InitJieBaUtil()
        {
            std::ifstream ifs(STOP_WORD_PATH);
            if (!ifs.is_open())
                std::cerr << "open STOP_WORD_PATH error" << std::endl;
            std::string stop_word;
            while (std::getline(ifs, stop_word))
            {
                _uset.emplace(std::move(stop_word));
            }
            ifs.close();
        }

    private:
        static JieBaUtil *_ins;
        static std::mutex _mutex;

        static cppjieba::Jieba _jieba;
        static std::unordered_set<std::string> _uset;
    };
    JieBaUtil *JieBaUtil::_ins = nullptr;
    std::mutex JieBaUtil::_mutex;
    cppjieba::Jieba JieBaUtil::_jieba(DICT_PATH, HMM_PATH, USER_DICT_PATH, IDF_PATH, STOP_WORD_PATH);
    std::unordered_set<std::string> JieBaUtil::_uset;

    // static cppjieba::Jieba jieba(DICT_PATH,
    //                              HMM_PATH,
    //                              USER_DICT_PATH,
    //                              IDF_PATH,
    //                              STOP_WORD_PATH);
    // class JieBaUtil
    // {
    // public:
    //     static void CutForSerach(const std::string &s, std::vector<std::string> *words)
    //     {
    //         jieba.CutForSearch(s, *words);
    //     }
    // };
}